/*
 * infra.c
 *
 * Created: 2012.11.22. 14:02:44
 *  Author: some00
 */ 
//before infra screw up

#include "infra.h"

//Global Variables
unsigned volatile int complete;
unsigned volatile int data[DATA_SIZE];
unsigned volatile int tempData[DATA_SIZE];
unsigned volatile int tempDataIndex;
unsigned volatile int timerOVF;
unsigned volatile int dataIndex;				//current bytes index
unsigned volatile int started;
volatile Button lastButton;			//last received command (for "repeat" command)
volatile int volBeforeMute;
volatile int mute = 0;
volatile int available = 0;

const int byteCode[37][5] =
{
	{0x02, 0xfc, 0x01, 0xfe, 0x01},							// button_on_off
	{0x02, 0xfc, 0x07, 0xf8, 0x01},							// button_mute
	{0x02, 0xfc, 0x03, 0xfc, 0x01},							// button_1
	{0x02, 0xfc, 0x05, 0xfa, 0x01},							// button_2
	{0x02, 0xfc, 0x0d, 0xf2, 0x01},							// button_3
	{0x02, 0xfc, 0x09, 0xf6, 0x01},							// button_4
	{0x02, 0xfc, 0x0b, 0xf4, 0x01},							// button_5
	{0x02, 0xfc, 0x0f, 0xf0, 0x01},							// button_6
	{0x02, 0xfc, 0x11, 0xee, 0x01},							// button_7
	{0x02, 0xfc, 0x15, 0xea, 0x01},							// button_8
	{0x02, 0xfc, 0x17, 0xe8, 0x01},							// button_9
	{0x02, 0xfc, 0x33, 0xcc, 0x01},							// button_i
	{0x02, 0xfc, 0x1d, 0xe2, 0x01},							// button_0
	{0x02, 0xfc, 0x35, 0xca, 0x01},							// button_epg
	{0x02, 0xfc, 0x31, 0xce, 0x01},							// button_vol_up
	{0x02, 0xfc, 0x21, 0xde, 0x01},							// button_vol_down
	{0x02, 0xfc, 0x3d, 0xc2, 0x01},							// button_menu
	{0x02, 0xfc, 0x1b, 0xe4, 0x01},							// button_txt
	{0x02, 0xfc, 0x27, 0xd8, 0x01},							// button_p_plus
	{0x02, 0xfc, 0x23, 0xdc, 0x01},							// button_p_minus
	{0x02, 0xfc, 0x2b, 0xd4, 0x01},							// button_up
	{0x02, 0xfc, 0x29, 0xd6, 0x01},							// button_left
	{0x02, 0xfc, 0x2f, 0xd0, 0x01},							// button_right
	{0x02, 0xfc, 0x2d, 0xd2, 0x01},							// button_down
	{0x02, 0xfc, 0x25, 0xda, 0x01},							// button_ok
	{0x02, 0xfc, 0x19, 0xe6, 0x01},							// button_exit
	{0x02, 0xfc, 0x1f, 0xe0, 0x01},							// button_opt
	{0x02, 0xfc, 0x8f, 0x70, 0x01},							// button_red
	{0x02, 0xfc, 0x83, 0x7c, 0x01},							// button_green
	{0x02, 0xfc, 0x85, 0x7a, 0x01},							// button_yellow
	{0x02, 0xfc, 0x3b, 0xc4, 0x01},							// button_blue
	{0x02, 0xfc, 0x89, 0x76, 0x01},							// button_msg
	{0x02, 0xfc, 0x8b, 0x74, 0x01},							// button_tv_stb
	{0x02, 0xfc, 0x8d, 0x72, 0x01},							// button_unknown
	{0x02, 0xfc, 0x81, 0x7e, 0x01},							// button_tv_r
	{0xff, 0xff, 0xff, 0xff, 0xff},							// repeat
	{0x00, 0x00, 0x00, 0x00, 0x00}							// invalid
};

int isEqual(int *a, const int * b)
{
	for(int i = 0; i < 5; i++)
	{
		if(a[i] != b[i]) return 0;
	}
	return 1;
}

Button bitsToButton()
{
	int temp[5];
	Button ret = 0;
	
	for(int i = 0; i < 5; i++) temp[i] = 0;
	
	int j = 0;
	for(int i = 1; i < tempDataIndex; i++)
	{
		if ( tempData[i] == 0 ) temp[j] &=	~( 1 << (i % 8) );
		if ( tempData[i] == 1 ) temp[j] |=	( 1 << (i  % 8) );
		
		if ( tempData[i] == 'w')
		{
			if ( (i - 1) == 0) return repeat;
			else return invalid;
		}
		
		if (i % 8 == 7) j++;
	}
	
	//for(int i = 0; i < 5; i++) USART_Transmit(temp[i]);
	
	for(ret = 0; ret < invalid; ret++)
	{
		if (isEqual(temp, byteCode[ret])) return ret;
	}

	return invalid;
}

//add the current command to the lifo
void addToLifo()
{
	Button pressed = bitsToButton();	
	
	if (pressed == repeat)
	{
		//if the button should be repeated
		if( repeatTypeButton(lastButton) )
		{
			pressed = lastButton;	
		}
	}		 
	else lastButton = pressed;
	
		
	if (pressed == invalid) return;
	
	int address = ButtonToAddress(pressed);
	if (address != -1)
	{
		
		Operation op;
		
		op.address = address;
		op.button = pressed;
		op.callback = &callBackFunction;
		
		if(pressed == button_on_off)
		{
			
		}
		else op.FlashType = 'D';		//ddc
		
		op.OpType = 'R';				//read
		op.value = 0;
		bufferAdd(op);
	}
}

//Interrupt Service Routines
ISR(INT0_vect)
{
	if (started == 0)
	{
		started = 1;
		TCNT1	= 0;
		TIFR1	= 0xFF;
		TIMSK1	= 0b00000010;
	}
	else
	{
		int temp = TCNT0;
		
		//OVF int enabled
		TCNT0	= 0;
		TIFR0	= 0xFF;
		TIMSK0	= 0b00000001;
		
		if(dataIndex < DATA_SIZE)
		{
			if (temp < 80)
			{
				data[dataIndex]	= 0;
			}
			else data[dataIndex] = 1;
			
			if (timerOVF == 1)
			{
				data[dataIndex] = 2;
				timerOVF = 0;
			}
			dataIndex++;
		}
	}
}
//Sample timer
ISR(TIMER0_OVF_vect)
{
	timerOVF = 1;
}

//Timeout timer
ISR(TIMER1_COMPA_vect)
{
	//Stop self
	TIMSK1 = 0x00;
	TCNT1	=	0;
	
	//Stop sample timer
	TIMSK0 = 0x00;
	
	if (dataIndex == 1)
	{
		data[dataIndex] = 'w';
		dataIndex++;
	}		
	//Set bit for log
	complete = 1;
	
	for(int i = 0; i < DATA_SIZE; i++)
	{
		tempData[i] = data[i];
	}
	tempDataIndex = dataIndex;
	
	InitInfra();
	
	available = 1;
}

//Initialize
void InitInfra()
{
	//Global Variables
	complete = 0;
	for(int i = 0; i < DATA_SIZE; i++) data[i] = 0;
	timerOVF = 0;
	dataIndex	= 0x00;
	started	= 0;
	available = 0;
	
	//Init Timer0
	TCCR0A	= 0x00;
	TCCR0B	= 0b00000100;
	//Interrupt disabled
	TIMSK0 = 0x00;

	
	//Init Timer1 - 70ms / 1024 divider
	TCCR1A	= 0x00;
	TCCR1B	= 0b00000101;
	TCCR1C	= 0b00000000;	//Compare A
	OCR1A	= 1094;
	TCNT1	= 0;
	//Interrupt disabled
	TIMSK1	= 0b00000000;
	
	//Init External Interrupt - INT0 - falling-edge
	//EICRA	= 0b00000010;
	//EIMSK	= 0b00000001;
	EICRA |= (1 << 1);
	EICRA &= ~(1 << 0);
	EIMSK |= (1 << 0);
}


void AddInfraButton()
{
	if(available)
	{
		available = 0;
		addToLifo();
	}	
}

//log infra received bits on uart
void logInfra()
{
	//for(int i = 0; i < dataIndex; i++) USART_Transmit(data[i] + '0');
	//USART_Transmit('\n');
}